#include "server.h"

struct cnfg_info cnfg_info;
struct stat_info stat_info;
struct operate_info operate_info;

extern int worker_start();
extern int listener_start();
extern int monitor_start();

static int _cnfg(char *argv0)
{/*{{{*/
    char buf[200];
    int res;
    int i;

    /*----- cnfg -----*/
#ifndef _MY_DEBUG
    char *svcenv_dir=getenv("SVCENV_DIR");
    if(!svcenv_dir)
    {
        fprintf(stderr, "agent: SVCENV_DIR not set\n");
        return(-1);
    }
#endif
    char *svcenv_cnfg=getenv("SVCENV_CNFG");
    if(!svcenv_cnfg)
    {
        fprintf(stderr, "agent: SVCENV_CNFG not set\n");
        return(-1);
    }
    CNFG cnfg;
    struct cnfg_property property;
    struct cnfg_property *array;
    int array_num;
    res=cnfg_load(svcenv_cnfg, &cnfg);
    if(res)
    {
        if(res > 0)
            fprintf(stderr, "agent: svcenv.cnfg line %d error\n",
                    res);
        else
            fprintf(stderr, "agent: load svcenv.cnfg fail, errcode:%d\n",
                    res);
        return(-1);
    }

    // ERRLOG
#ifdef _MY_DEBUG
    CLR_BUF(cnfg_info.errlog_location);
    init_errlog(argv0, NULL);
#else
    sprintf(cnfg_info.errlog_location, "%s/log", svcenv_dir);
    res=cnfg_get_property(cnfg, "ERRLOG", "LOCATION", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr,
                    "agent: get ERRLOG.LOCATION fail, errcode:%d\n",
                    res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(property.value[0] == '/')
                strcpy(cnfg_info.errlog_location, property.value);
            else
                sprintf(cnfg_info.errlog_location, "%s/%s",
                        svcenv_dir, property.value);
        }
    }
    res=init_errlog(argv0, cnfg_info.errlog_location);
    if(res)
    {
        fprintf(stderr, "agent: init_errlog fail, errcode:%d\n", res);
        return(-1);
    }
#endif

    // IPCKEY
    res=cnfg_get_property(cnfg, "GLOBAL", "IPCKEY", 0, &property);
    if(res)
    {
        sprintf(buf, "agent: get IPCKEY in svcenv.cnfg fail, errcode:%d",
                res);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || !str_is_dec(property.value))
    {
        sprintf(buf, "agent: IPCKEY invalid in svcenv.cnfg");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    cnfg_info.ipckey=atoi(property.value);

    /*--- AGENT ---*/
    // SERVER_PORT
    res=cnfg_get_property(cnfg, "AGENT", "SERVER_PORT", 0, &property);
    if(res)
    {
        sprintf(buf, "agent: get AGENT.SERVER_PORT fail, errcode:%d",
                res);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        sprintf(buf, "agent: AGENT.SERVER_PORT invalid in svcenv.cnfg");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    cnfg_info.server_port=res;
    // MONITOR_PORT
    res=cnfg_get_property(cnfg, "AGENT", "MONITOR_PORT", 0, &property);
    if(res)
    {
        sprintf(buf, "agent: get AGENT.MONITOR_PORT fail, errcode:%d",
                res);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        sprintf(buf, "agent: AGENT.MONITOR_PORT invalid in svcenv.cnfg");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    cnfg_info.monitor_port=res;
    // THREADS
    res=cnfg_get_property(cnfg, "AGENT", "THREADS", 0, &property);
    if(res)
    {
        sprintf(buf, "agent: get AGENT.THREADS fail, errcode:%d", res);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        sprintf(buf, "agent: AGENT.THREADS invalid in svcenv.cnfg");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    cnfg_info.threads=atoi(property.value);

    /*--- SVCNODE ---*/
    array_num=cnfg_property_array(cnfg, "SVCNODE", 0, &array);
    if(array_num < 0)
    {
        sprintf(buf, "agent: get SVCNODE array fail, errcode:%d", res);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(array_num > 0)
    {/*{{{*/
        ALLOC_ARRAY_DOERR(cnfg_info._svcnode_.svcnode,
                struct _cnfg_svcnode, array_num,
                cnfg_info._svcnode_.num,
                sprintf(buf,
                    "agent: alloc cnfg_info._svcnode_.svcnode fail");
                fprintf(stderr, "%s\n", buf); errlog(buf);
                return(-1);
                );
        for(i=0; i<array_num; ++i)
        {
            struct _cnfg_svcnode *cnfg_sn=
                &cnfg_info._svcnode_.svcnode[i];
            if(array[i].type != CNFG_PROPERTY_COMPOSITE)
            {
                sprintf(buf, "agent: svcnode(%d) invalid", i);
                fprintf(stderr, "%s\n", buf); errlog(buf);
                return(-1);
            }
            strcpy(cnfg_sn->name, array[i].name);
            res=cnfg_get_subproperty(cnfg, "SVCNODE",
                    array[i].name, "ADDR", 0, &property);
            if(res || BUF_IS_CLR(property.value) ||
                    strlen(property.value) > LONG_FILE_NM_SIZE)
            {
                sprintf(buf, "agent: SVCNODE.%s.ADDR invalid",
                        array[i].name);
                fprintf(stderr, "%s\n", buf); errlog(buf);
                return(-1);
            }
            strcpy(cnfg_sn->addr, property.value);
            res=cnfg_get_subproperty(cnfg, "SVCNODE", array[i].name,
                    "MODE", 0, &property);
            if(res)
            {
                if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND) 
                {
                    sprintf(buf,
                            "agent: get SVCNODE.%s.MODE fail, "
                            "errcode:%d",
                            array[i].name, res);
                    fprintf(stderr, "%s\n", buf); errlog(buf);
                    return(-1);
                }
                cnfg_sn->mode=SN_MODE_PERMANENT;
            }
            else
            {
                if(!BUF_IS_CLR(property.value) &&
                        strcasecmp(property.value, "ONESHOT") == 0)
                    cnfg_sn->mode=SN_MODE_ONESHOT;
                else
                    cnfg_sn->mode=SN_MODE_PERMANENT;
            }
        }
        free(array);
    }/*}}}*/

    cnfg_free(cnfg);

    return(0);
}/*}}}*/

static int _start()
{/*{{{*/
    char buf[200];

    sig_ignore(SIGPIPE);
    ep_init();
    ossl_init_mt();

    pthread_mutex_init(&stat_info._svr_.lock, NULL);
    int i;
    for(i=0; i<SVR_MAX_NUM; ++i)
    {
        struct _svr_info *svr=&stat_info._svr_.svrs[i];
        CLR_BUF(svr->name);
        svr->pid=-1;
        listp_init(&svr->svcs);
    }
    rb_create(TREE_KEY_STRING, &stat_info._svr_.svcs);

    if(worker_start())
    {
        sprintf(buf, "agent: worker start fail");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(listener_start())
    {
        sprintf(buf, "agent: listener start fail");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }

    return(monitor_start());
}/*}}}*/

int main(int argc, char *argv[])
{
#ifndef _MY_DEBUG
    if(daemon(1, 1) == -1)
    {
        fprintf(stderr, "daemon fail: %d\n", get_last_error(NULL)); 
        return(1);
    }
#endif
    if(_cnfg(argv[0])) return(-1);
    return(_start());
}
